home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 2010 April / PCWorld0410.iso / hity wydania / Ubuntu 9.10 PL / karmelkowy-koliberek-9.10-netbook-remix-PL.iso / casper / filesystem.squashfs / usr / share / pyshared / cupshelpers / openprinting.py < prev    next >
Text File  |  2009-10-19  |  17KB  |  434 lines

  1. #!/usr/bin/env python
  2.  
  3. ## system-config-printer
  4.  
  5. ## Copyright (C) 2008 Red Hat, Inc.
  6. ## Copyright (C) 2008 Till Kamppeter <till.kamppeter@gmail.com>
  7.  
  8. ## This program is free software; you can redistribute it and/or modify
  9. ## it under the terms of the GNU General Public License as published by
  10. ## the Free Software Foundation; either version 2 of the License, or
  11. ## (at your option) any later version.
  12.  
  13. ## This program is distributed in the hope that it will be useful,
  14. ## but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16. ## GNU General Public License for more details.
  17.  
  18. ## You should have received a copy of the GNU General Public License
  19. ## along with this program; if not, write to the Free Software
  20. ## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  21.  
  22. import urllib, httplib, platform, threading, tempfile, traceback
  23. import os, sys
  24. from xml.etree.ElementTree import XML
  25. from . import Device
  26.  
  27. __all__ = ['OpenPrinting']
  28.  
  29. def _normalize_space (text):
  30.     result = text.strip ()
  31.     result = result.replace ('\n', ' ')
  32.     i = result.find ('  ')
  33.     while i != -1:
  34.         result = result.replace ('  ', ' ')
  35.         i = result.find ('  ')
  36.     return result
  37.  
  38. class _QueryThread (threading.Thread):
  39.     def __init__ (self, parent, parameters, callback, user_data=None):
  40.         threading.Thread.__init__ (self)
  41.         self.parent = parent
  42.         self.parameters = parameters
  43.         self.callback = callback
  44.         self.user_data = user_data
  45.  
  46.         self.setDaemon (True)
  47.  
  48.     def run (self):
  49.         # CGI script to be executed
  50.         query_command = "/query.cgi"
  51.         # Headers for the post request
  52.         headers = {"Content-type": "application/x-www-form-urlencoded",
  53.                    "Accept": "text/plain"}
  54.         params = ("%s&uilanguage=%s&locale=%s" %
  55.                   (urllib.urlencode (self.parameters),
  56.                    self.parent.language[0],
  57.                    self.parent.language[0]))
  58.         self.url = "http://%s%s?%s" % (self.parent.base_url, query_command, params)
  59.         # Send request
  60.         result = None
  61.         status = 1
  62.         try:
  63.             conn = httplib.HTTPConnection(self.parent.base_url)
  64.             conn.request("POST", query_command, params, headers)
  65.             resp = conn.getresponse()
  66.             status = resp.status
  67.             if status == 200:
  68.                 result = resp.read()
  69.             conn.close()
  70.         except:
  71.             result = sys.exc_info ()
  72.  
  73.         if status == 200:
  74.             status = 0
  75.  
  76.         if self.callback != None:
  77.             self.callback (status, self.user_data, result)
  78.  
  79. class OpenPrinting:
  80.     def __init__(self, language=None):
  81.         """
  82.         @param language: language, as given by the first element of
  83.         locale.setlocale().
  84.         @type language: string
  85.         """
  86.         if language == None:
  87.             import locale
  88.             try:
  89.                 language = locale.getlocale(locale.LC_MESSAGES)
  90.             except locale.Error, e:
  91.                 language = 'C'
  92.         self.language = language
  93.  
  94.         # XXX Read configuration file.
  95.         self.base_url = "www.openprinting.org"
  96.  
  97.         # Restrictions on driver choices XXX Parameters to be taken from
  98.         # config file
  99.         self.onlyfree = 0
  100.         self.onlymanufacturer = 0
  101.  
  102.     def cancelOperation(self, handle):
  103.         """
  104.         Cancel an operation.
  105.  
  106.         @param handle: query/operation handle
  107.         """
  108.         # Just prevent the callback.
  109.         try:
  110.             handle.callback = None
  111.         except:
  112.             pass
  113.  
  114.     def webQuery(self, parameters, callback, user_data=None):
  115.         """
  116.         Run a web query for a driver.
  117.  
  118.         @type parameters: dict
  119.         @param parameters: URL parameters
  120.         @type callback: function
  121.         @param callback: callback function, taking (integer, user_data, string)
  122.         parameters with the first parameter being the status code, zero for
  123.         success
  124.         @return: query handle
  125.         """
  126.         the_thread = _QueryThread (self, parameters, callback, user_data)
  127.         the_thread.start()
  128.         return the_thread
  129.  
  130.     def searchPrinters(self, searchterm, callback, user_data=None):
  131.         """
  132.         Search for printers using a search term.
  133.  
  134.         @type searchterm: string
  135.         @param searchterm: search term
  136.         @type callback: function
  137.         @param callback: callback function, taking (integer, user_data, string)
  138.         parameters with the first parameter being the status code, zero for
  139.         success
  140.         @return: query handle
  141.         """
  142.  
  143.         def parse_result (status, data, result):
  144.             (callback, user_data) = data
  145.             if status != 0:
  146.                 callback (status, user_data, result)
  147.                 return
  148.  
  149.             status = 0
  150.             printers = {}
  151.             try:
  152.                 root = XML (result)
  153.                 # We store the printers as a dict of:
  154.                 # foomatic_id: displayname
  155.  
  156.                 for printer in root.findall ("printer"):
  157.                     id = printer.find ("id")
  158.                     make = printer.find ("make")
  159.                     model = printer.find ("model")
  160.                     if id != None and make != None and model != None:
  161.                         idtxt = id.text
  162.                         maketxt = make.text
  163.                         modeltxt = model.text
  164.                         if idtxt and maketxt and modeltxt:
  165.                             printers[idtxt] = maketxt + " " + modeltxt
  166.             except:
  167.                 status = 1
  168.                 printers = sys.exc_info ()
  169.  
  170.             try:
  171.                 callback (status, user_data, printers)
  172.             except:
  173.                 (type, value, tb) = sys.exc_info ()
  174.                 tblast = traceback.extract_tb (tb, limit=None)
  175.                 if len (tblast):
  176.                     tblast = tblast[:len (tblast) - 1]
  177.                 extxt = traceback.format_exception_only (type, value)
  178.                 for line in traceback.format_tb(tb):
  179.                     print (line.strip ())
  180.                 print (extxt[0].strip ())
  181.  
  182.         # Common parameters for the request
  183.         params = { 'type': 'printers',
  184.                    'printer': searchterm,
  185.                    'format': 'xml' }
  186.         return self.webQuery(params, parse_result, (callback, user_data))
  187.  
  188.     def listDrivers(self, model, callback, user_data=None, extra_options=None):
  189.         """
  190.         Obtain a list of printer drivers.
  191.  
  192.         @type model: string or cupshelpers.Device
  193.         @param model: foomatic printer model string or a cupshelpers.Device
  194.         object
  195.         @type callback: function
  196.         @param callback: callback function, taking (integer, user_data, string)
  197.         parameters with the first parameter being the status code, zero for
  198.         success
  199.         @type extra_options: string -> string dictionary
  200.         @param extra_options: Additional search options, see
  201.         http://www.linuxfoundation.org/en/OpenPrinting/Database/Query
  202.         @return: query handle
  203.         """
  204.  
  205.         def parse_result (status, data, result):
  206.             (callback, user_data) = data
  207.             if status != 0:
  208.                 callback (status, user_data, result)
  209.  
  210.             try:
  211.                 root = XML (result)
  212.                 drivers = {}
  213.                 # We store the drivers as a dict of:
  214.                 # foomatic_id:
  215.                 #   { 'name': name,
  216.                 #     'url': url,
  217.                 #     'supplier': supplier,
  218.                 #     'license': short license string e.g. GPLv2,
  219.                 #     'licensetext': license text (Plain text),
  220.                 #     'nonfreesoftware': Boolean,
  221.                 #     'thirdpartysupplied': Boolean,
  222.                 #     'manufacturersupplied': Boolean,
  223.                 #     'patents': Boolean,
  224.                 #     'supportcontacts' (optional):
  225.                 #       list of { 'name',
  226.                 #                 'url',
  227.                 #                 'level',
  228.                 #               }
  229.                 #     'shortdescription': short description,
  230.                 #     'recommended': Boolean,
  231.                 #     'functionality':
  232.                 #       { 'text': integer percentage,
  233.                 #         'lineart': integer percentage,
  234.                 #         'graphics': integer percentage,
  235.                 #         'photo': integer percentage,
  236.                 #         'speed': integer percentage,
  237.                 #       }
  238.                 #     'packages' (optional):
  239.                 #       { arch:
  240.                 #         { file:
  241.                 #           { 'url': url,
  242.                 #             'realversion': upstream version string,
  243.                 #             'version': packaged version string,
  244.                 #             'release': package release string
  245.                 #           }
  246.                 #         }
  247.                 #       }
  248.                 #     'ppds' (optional):
  249.                 #       URL string list
  250.                 #   }
  251.                 # There is more information in the raw XML, but this
  252.                 # can be added to the Python structure as needed.
  253.  
  254.                 for driver in root.findall ('driver'):
  255.                     id = driver.attrib.get ('id')
  256.                     if id == None:
  257.                         continue
  258.  
  259.                     dict = {}
  260.                     for attribute in ['name', 'url', 'supplier', 'license',
  261.                                       'shortdescription' ]:
  262.                         element = driver.find (attribute)
  263.                         if element != None and element.text != None:
  264.                             dict[attribute] = _normalize_space (element.text)
  265.  
  266.                     element = driver.find ('licensetext')
  267.                     if element != None:
  268.                         dict['licensetext'] = element.text
  269.  
  270.                     for boolean in ['nonfreesoftware', 'recommended',
  271.                                     'patents', 'thirdpartysupplied',
  272.                                     'manufacturersupplied']:
  273.                         dict[boolean] = driver.find (boolean) != None
  274.  
  275.                     # Make a 'freesoftware' tag for compatibility with
  276.                     # how the OpenPrinting API used to work (see trac
  277.                     # #74).
  278.                     dict['freesoftware'] = not dict['nonfreesoftware']
  279.  
  280.                     supportcontacts = []
  281.                     container = driver.find ('supportcontacts')
  282.                     if container != None:
  283.                         for sc in container.findall ('supportcontact'):
  284.                             supportcontact = {}
  285.                             if sc.text != None:
  286.                                 supportcontact['name'] = \
  287.                                     _normalize_space (sc.text)
  288.                             else:
  289.                                 supportcontact['name'] = ""
  290.                             supportcontact['url'] = sc.attrib.get ('url')
  291.                             supportcontact['level'] = sc.attrib.get ('level')
  292.                             supportcontacts.append (supportcontact)
  293.  
  294.                     if supportcontacts:
  295.                         dict['supportcontacts'] = supportcontacts
  296.  
  297.                     if not dict.has_key ('name') or not dict.has_key ('url'):
  298.                         continue
  299.  
  300.                     container = driver.find ('functionality')
  301.                     if container != None:
  302.                         functionality = {}
  303.                         for attribute in ['text', 'lineart', 'graphics',
  304.                                           'photo', 'speed']:
  305.                             element = container.find (attribute)
  306.                             if element != None:
  307.                                 functionality[attribute] = element.text
  308.                         if functionality:
  309.                             dict[container.tag] = functionality
  310.  
  311.                     packages = {}
  312.                     container = driver.find ('packages')
  313.                     if container != None:
  314.                         for arch in container.getchildren ():
  315.                             rpms = {}
  316.                             for package in arch.findall ('package'):
  317.                                 rpm = {}
  318.                                 for attribute in ['realversion','version',
  319.                                                   'release', 'url', 'pkgsys']:
  320.                                     element = package.find (attribute)
  321.                                     if element != None:
  322.                                         rpm[attribute] = element.text
  323.  
  324.                                 repositories = package.find ('repositories')
  325.                                 if repositories != None:
  326.                                     for pkgsys in repositories.getchildren ():
  327.                                         rpm.setdefault('repositories', {})[pkgsys.tag] = pkgsys.text
  328.  
  329.                                 rpms[package.attrib['file']] = rpm
  330.                             packages[arch.tag] = rpms
  331.  
  332.                     if packages:
  333.                         dict['packages'] = packages
  334.  
  335.                     ppds = []
  336.                     container = driver.find ('ppds')
  337.                     if container != None:
  338.                         for each in container.getchildren ():
  339.                             ppds.append (each.text)
  340.  
  341.                     if ppds:
  342.                         dict['ppds'] = ppds
  343.  
  344.                     drivers[id] = dict
  345.                 callback (0, user_data, drivers)
  346.             except:
  347.                 callback (1, user_data, sys.exc_info ())
  348.  
  349.         if isinstance(model, Device):
  350.             model = model.id
  351.  
  352.         params = { 'type': 'drivers',
  353.                    'moreinfo': '1',
  354.                    'showprinterid': '1',
  355.                    'onlynewestdriverpackages': '1',
  356.                    'architectures': platform.machine(),
  357.                    'noobsoletes': '1',
  358.                    'onlyfree': str (self.onlyfree),
  359.                    'onlymanufacturer': str (self.onlymanufacturer),
  360.                    'printer': model,
  361.                    'format': 'xml'}
  362.         if extra_options:
  363.             params.update(extra_options)
  364.         return self.webQuery(params, parse_result, (callback, user_data))
  365.  
  366. def _simple_gui ():
  367.     import gtk, pprint
  368.     gtk.gdk.threads_init ()
  369.     class QueryApp:
  370.         def __init__(self):
  371.             self.openprinting = OpenPrinting()
  372.             self.main = gtk.Dialog ("OpenPrinting query application",
  373.                                     None,
  374.                                     gtk.DIALOG_MODAL | gtk.DIALOG_NO_SEPARATOR,
  375.                                     (gtk.STOCK_CLOSE, gtk.RESPONSE_CLOSE,
  376.                                      "Search", 10,
  377.                                      "List", 20))
  378.             self.main.set_border_width (6)
  379.             self.main.vbox.set_spacing (2)
  380.             vbox = gtk.VBox (False, 6)
  381.             self.main.vbox.pack_start (vbox, True, True, 0)
  382.             vbox.set_border_width (6)
  383.             self.entry = gtk.Entry ()
  384.             vbox.pack_start (self.entry, False, False, 6)
  385.             sw = gtk.ScrolledWindow ()
  386.             self.tv = gtk.TextView ()
  387.             sw.add (self.tv)
  388.             vbox.pack_start (sw, True, True, 6)
  389.             self.main.connect ("response", self.response)
  390.             self.main.show_all ()
  391.  
  392.         def response (self, dialog, response):
  393.             if (response == gtk.RESPONSE_CLOSE or
  394.                 response == gtk.RESPONSE_DELETE_EVENT):
  395.                 gtk.main_quit ()
  396.  
  397.             if response == 10:
  398.                 # Run a query.
  399.                 self.openprinting.searchPrinters (self.entry.get_text (),
  400.                                                   self.search_printers_callback)
  401.  
  402.             if response == 20:
  403.                 self.openprinting.listDrivers (self.entry.get_text (),
  404.                                                self.list_drivers_callback)
  405.  
  406.         def search_printers_callback (self, status, user_data, printers):
  407.             if status != 0:
  408.                 raise printers[1]
  409.  
  410.             text = ""
  411.             for printer in printers.values ():
  412.                 text += printer + "\n"
  413.             gtk.gdk.threads_enter ()
  414.             self.tv.get_buffer ().set_text (text)
  415.             gtk.gdk.threads_leave ()
  416.  
  417.         def list_drivers_callback (self, status, user_data, drivers):
  418.             if status != 0:
  419.                 raise drivers[1]
  420.  
  421.             text = pprint.pformat (drivers)
  422.             gtk.gdk.threads_enter ()
  423.             self.tv.get_buffer ().set_text (text)
  424.             gtk.gdk.threads_leave ()
  425.  
  426.         def query_callback (self, status, user_data, result):
  427.             gtk.gdk.threads_enter ()
  428.             self.tv.get_buffer ().set_text (str (result))
  429.             file ("result.xml", "w").write (str (result))
  430.             gtk.gdk.threads_leave ()
  431.  
  432.     q = QueryApp()
  433.     gtk.main ()
  434.